package com.weizhu.swufer.core.client;

import cn.hutool.core.util.StrUtil;
import com.weizhu.swufer.autoconfiguration.SwuferProperties;
import com.weizhu.swufer.core.annotation.SwuferReference;
import com.weizhu.swufer.core.annotation.SwuferService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


public class SwuferReferenceInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {

    private SwuferProperties swuferProperties;

    private ApplicationContext applicationContext;
    
    public SwuferReferenceInstantiationAwareBeanPostProcessor(SwuferProperties swuferProperties,ApplicationContext applicationContext) {
        this.swuferProperties = swuferProperties;
        this.applicationContext = applicationContext;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class<?> beanClass = bean.getClass();
        while (!Object.class.equals(beanClass) && beanClass != null){
            Field[] fields = beanClass.getDeclaredFields();
            for (Field field : fields) {
                SwuferReference annotation = field.getAnnotation(SwuferReference.class);
                String referService = null;
                Class<?> tClass = null;
                if (annotation != null){
                    referService = annotation.referService();
                    try {
                        tClass = Class.forName(referService);
                    }catch (Exception e){

                    }
                    if (tClass == null){
                        Class<?> type = field.getType();
                        if (type.isInterface()){
                            tClass = type;
                            referService = type.getName();
                        }else {
                            Class<?>[] interfaces = type.getInterfaces();
                            if (interfaces.length != 1){
                                throw new RuntimeException("未指定要代理的Rpc接口");
                            }else {
                                tClass = interfaces[0];
                                referService = interfaces[0].getName();
                            }
                        }
                    }
                    //注册mockService
                    String mockService = annotation.failBackMockService();
                    if (!mockService.equals("")){
                        MockServiceManager.getInstance().getMockServiceMap().put(referService,getMockServiceBean(mockService));
                    }
                }else {
                    continue;
                }
                ReferenceConfig referenceConfig = new ReferenceConfig();
                referenceConfig.setReferServiceName(referService);
                referenceConfig.settClass(tClass);
                referenceConfig.setTargetAddress(annotation.targetAddress());
                referenceConfig.setAsync(annotation.async());
                if (annotation.maxWaitTime() > 0){
                    referenceConfig.setMaxWaitTime(annotation.maxWaitTime());
                }
                Object proxy = null;

                if (tClass == GenericService.class){
                    proxy = new DefaultGenericService(referenceConfig);
                }
                //get from Local JVM
                if (applicationContext != null && proxy == null && annotation.targetAddress().equals("")){
                    try {
                        proxy = applicationContext.getBean(tClass);
                        Class<?> localJVMServiceClass = proxy.getClass();
                        if (localJVMServiceClass.getAnnotation(SwuferService.class) == null){
                            proxy = null;
                            throw new IllegalStateException("not local swufer service");
                        }
                    }catch (Exception e){
                        System.err.println("not found impl in local jvm");
                    }

                }
                //get from remote
                if (proxy == null){
                    proxy = Proxy.newProxyInstance(tClass.getClassLoader(), new Class[]{tClass},
                            new ReferenceProxyHandler(referenceConfig));
                }

                try {
                    if (!field.isAccessible()) {
                        field.setAccessible(true);
                    }
                    field.set(bean, proxy);
                } catch (Throwable e) {
                    e.printStackTrace();
                }

            }
            beanClass = beanClass.getSuperclass();
        }
        return bean;
    }

    private Object getMockServiceBean(String name){
        if (applicationContext != null){
            try {
                return applicationContext.getBean(name);
            }catch (Exception e){
                e.printStackTrace();
                throw new IllegalStateException("can not find bean in spring,please ensure bean with @Component or @Service");
            }
        }
        throw new IllegalStateException("spring init error");
    }

}
